#include"PageCache.hpp"
#include"CentralCache.hpp"
PageCache PageCache::_sInst;

Span* PageCache::NewSpan(size_t k)//获取k个页的span
{
    assert(k>0);
    if(k>NPAGES-1)
    {
        void* ptr=SystemAlloc(k);
        //Span* span=new Span;
        Span* span=_spanPool.New();

        span->_pageId=(PAGE_ID)ptr>>PAGE_SHIFT;
        span->_n=k;
        //_idSpanMap[span->_pageId]=span;
        _idSpanMap.set(span->_pageId, span);

        return span;
    }
    if(!_spanLists[k].Empty())
    {
        Span* kSpan = static_cast<Span*>(_spanLists[k].PopFront());
       for(PAGE_ID i=0;i<kSpan->_n;++i)
       {
           //_idSpanMap[kSpan->_pageId+i]=kSpan;
           _idSpanMap.set(kSpan->_pageId + i, kSpan);
       }
       return kSpan;

    }
    for(size_t i=k+1;i<NPAGES;++i)
    {
        if(!_spanLists[i].Empty())
        {
            Span* nSpan = static_cast<Span*>(_spanLists[i].PopFront());
           
            Span* kSpan=new Span;
          //Span* kSpan=_spanPool.New();

            kSpan->_pageId=nSpan->_pageId;
            kSpan->_n=k;

            nSpan->_pageId+=k;
            nSpan->_n-=k;

            _spanLists[nSpan->_n].PushFront(nSpan);
            //_idSpanMap[nSpan->_pageId]=nSpan;
            //_idSpanMap[nSpan->_pageId+nSpan->_n-1]=nSpan;
            
            _idSpanMap.set(nSpan->_pageId , nSpan);
            _idSpanMap.set(nSpan->_pageId + nSpan->_n - 1, nSpan);



            for(PAGE_ID i=0;i<kSpan->_n;++i)
            {
                //_idSpanMap[kSpan->_pageId+i]=kSpan;
                _idSpanMap.set(kSpan->_pageId + i, kSpan);
            }
            //cout<<"test"<<endl;
            return kSpan;
        }
    }
    //Span* bigSpan=new Span;
    Span* bigSpan=_spanPool.New();

    void* ptr=SystemAlloc(NPAGES-1);
    bigSpan->_pageId=(PAGE_ID)ptr>>PAGE_SHIFT;
    bigSpan->_n=NPAGES-1;
    _spanLists[bigSpan->_n].PushFront(bigSpan);
    return NewSpan(k);
}
void PageCache::ReleaseSpanToPageCache(Span* span)//将span回收到pagecache中
{
    if(span->_n>NPAGES-1)
    {
        void* ptr=(void*)(span->_pageId<<PAGE_SHIFT);
        SystemFree(ptr,span->_n);
        //delete span;
        _spanPool.Delete(span);
        return;
    }
    while(1)
    {
        PAGE_ID prevId=span->_pageId-1;
        /*auto ret=_idSpanMap.find(prevId);
        if(ret==_idSpanMap.end())
        {
            break;
        }*/
        //Span* prevSpan=ret->second;
         Span* ret=(Span*)_idSpanMap.get(prevId);
       
         if(ret==nullptr)
         {
             break;
         }
        
          Span* prevSpan=ret;
        if(prevSpan->_isUse == true)
        {
            break;
        }
        /*if (prevSpan->_isUse.load()== true)
        {
            break;
        }*/
        if(prevSpan->_n+span->_n>NPAGES-1)
        {
            break;
        }
        span->_pageId=prevSpan->_pageId;
        span->_n+=prevSpan->_n;
        _spanLists[prevSpan->_n].Erase(prevSpan);
        _spanPool.Delete(prevSpan);
        //delete prevSpan;
    }
    while(1)
    {
        PAGE_ID nextId=span->_pageId+span->_n;
        /*auto ret=_idSpanMap.find(nextId);
        if(ret==_idSpanMap.end())
        {
            break;
        }*/
        Span* ret = (Span*)_idSpanMap.get(nextId);
        if (ret == nullptr)
        {
            break;
        }
        //Span* nextSpan=ret->second;
        Span* nextSpan = ret;
        /*if(nextSpan->_isUse.load() == true)
        {
            break;
        }*/
        if (nextSpan->_isUse == true)
        {
            break;
        }
        
        if(nextSpan->_n+span->_n>NPAGES-1)
        {
            break;
        }
        span->_n+=nextSpan->_n;
        _spanLists[nextSpan->_n].Erase(nextSpan);
        //delete nextSpan;
        _spanPool.Delete(nextSpan);
    }
    _spanLists[span->_n].PushFront(span);
    //_idSpanMap[span->_pageId]=span;
    //_idSpanMap[span->_pageId+span->_n-1]=span;

    _idSpanMap.set(span->_pageId, span);
    _idSpanMap.set(span->_pageId + span->_n - 1, span);

    //span->_isUse.store(false);
    span->_isUse = false;
}
Span* PageCache::MapObjectToSpan(void* obj)//获取从对象到span的映射
{
    PAGE_ID id=(PAGE_ID)obj>>PAGE_SHIFT;
    /*std::unique_lock<std::mutex> lock(_pageMtx);
    auto ret=_idSpanMap.find(id);
    if(ret!=_idSpanMap.end())
    {
        return ret->second;
    }
    else
    {
        assert(false);
        return nullptr;
    }*/
    Span* ret = (Span * )_idSpanMap.get(id);
    assert(ret != nullptr);
    return ret;
}

std::mutex _pageMtx;//pagecache的互斥锁